﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace UsandoSprites
{
    public abstract class Sprite
    {
        private Texture2D textura;
        protected Vector2 posicaoXY;
        protected Point frameBounder;
        private Point colisaoBounder;
        private Point frame;
        private Point sheetFrameSize;
        private int updateLastFrameTime;
        private int milisegundosPorFrame;
        protected Vector2 velocidade;
        private float profundidade;

        /// <summary>
        /// Constuindo  construtor da classe
        /// </summary>
        /// <param name="textura"></param>
        /// <param name="posicaoXY"></param>
        /// <param name="frameBounder"></param>
        /// <param name="colisaoBounder"></param>
        /// <param name="frame"></param>
        /// <param name="sheetFrameSize"></param>
        /// <param name="updateLastFrameTime"></param>
        /// <param name="milisegundosPorFrame"></param>
        /// <param name="speed"></param>
        /// <param name="profundidade"></param>
       
        public Sprite(  Texture2D textura, Vector2 posicaoXY, Point frameBounder, Point colisaoBounder, 
                        Point frame, Point sheetFrameSize, int updateLastFrameTime, int milisegundosPorFrame, 
                        Vector2 speed, float profundidade)
        {
            this.textura = textura;
            this.posicaoXY = posicaoXY;
            this.frameBounder = frameBounder;
            this.colisaoBounder = colisaoBounder;
            this.frame = frame;
            this.sheetFrameSize = sheetFrameSize;
            this.updateLastFrameTime = updateLastFrameTime;
            this.milisegundosPorFrame = milisegundosPorFrame;
            this.velocidade = speed;
            this.profundidade = profundidade;

        }
        
        /// <summary>
        /// Método que podes er subscrito indicando o comportamento de como draw deve trabalhar
        /// </summary>
        /// <param name="gameTime"></param>
        /// <param name="spriteBatch"></param>
        public virtual void Draw(GameTime gameTime, SpriteBatch spriteBatch)
        {
            spriteBatch.Draw(textura, posicaoXY, new Rectangle(frame.X * frameBounder.X, frame.Y * frameBounder.Y, frameBounder.X, frameBounder.Y), 
                Color.White, 0f, Vector2.Zero,1f, SpriteEffects.None, profundidade);
        }

        /// <summary>
        /// Método que pode ser subscrito informando o comportamento de como modifica e atualiza o desenho a ser animado na folha de sprites (sheetFrame)
        /// </summary>
        /// <param name="gameTime"></param>
        /// <param name="retangulo"></param>
        public virtual void Update(GameTime gameTime, Rectangle retangulo)
        {
            updateLastFrameTime += gameTime.ElapsedGameTime.Milliseconds;
            if (updateLastFrameTime > milisegundosPorFrame)
            {
                updateLastFrameTime = 0;

                if (++frame.X >= sheetFrameSize.X)
                {
                    frame.X = 0;
                    if (++frame.Y > sheetFrameSize.Y)
                    {
                        frame.Y = 0;
                    }
                }
            }
        }

        /// <summary>
        /// Outra implementação para o comportamento de sprite
        /// </summary>
        /// <param name="gameTime"></param>
        /// <param name="frameAtivo"></param>
        public virtual void Update(GameTime gameTime, Point frameAtivo)
        {
            updateLastFrameTime += gameTime.ElapsedGameTime.Milliseconds;
            if (updateLastFrameTime > milisegundosPorFrame)
            {
                updateLastFrameTime = 0;
                frame = frameAtivo;
            }
        }

        /// <summary>
        /// retorna o bounder do frame ativo
        /// </summary>
        public virtual Rectangle bounderSprite
        {
            get
            {
                return new Rectangle((int)posicaoXY.X, (int)posicaoXY.Y, frameBounder.X, frameBounder.Y);
            }
        }

        /// <summary>
        /// Método abstrato indica que é necessário implementar funcionalidade a este na classe derivada
        /// </summary>
        public abstract Vector2 Direcao
        {
            get;
        }

       
        
       
    }
}


    

